﻿using System;
using System.Linq;
using System.Collections.Generic;
using Domain.Core;
using Domain.MainModule.Entities;
using Domain.MainModule.Identities;
using Domain.MainModule.IdentityTypes;

namespace Application.MainModule.IdentitiesManagement
{
    public class IdentityManagementService : IIdentityManagementService, IDisposable
    {
        #region private properties

        private IIdentityRepository IdentityRepository
        {
            get;
            set;
        }

        private IIdentityTypeRepository IdentityTypeRepository
        {
            get;
            set;
        }

        #endregion

        #region constructor

        /// <summary>
        /// Default constructor for IdentityService.
        /// </summary>
        /// <param name="identityRepository">IdentityRepository dependency, usually this is resolved by IoC</param>
        /// <param name="identityTypeRepository">IdentityTypeRepository dependency, usually this is resolved by IoC</param>
        public IdentityManagementService(IIdentityRepository identityRepository, IIdentityTypeRepository identityTypeRepository)
        {
            if (identityRepository == (IIdentityRepository)null)
            {
                throw new ArgumentNullException(Resources.Messages.exception_DependenciesAreNotInitialized);
            }

            if (identityTypeRepository == (IIdentityTypeRepository)null)
            {
                throw new ArgumentNullException(Resources.Messages.exception_DependenciesAreNotInitialized);
            }

            this.IdentityRepository = identityRepository;
            this.IdentityTypeRepository = identityTypeRepository;
        }

        #endregion

        #region IIdentityService implementations

        public void AddIdentity(Identity identity)
        {
            IUnitOfWork unitOfWork = this.IdentityRepository.UnitOfWork as IUnitOfWork;
            this.IdentityRepository.Add(identity);
            unitOfWork.Commit();
        }

        public void ChangeIdentity(Identity identity)
        {
            IUnitOfWork unitOfWork = this.IdentityRepository.UnitOfWork as IUnitOfWork;
            this.IdentityRepository.Modify(identity);
            unitOfWork.CommitAndRefreshChanges();
        }

        public Identity FindIdentityById(Guid identityId)
        {
            IdentityIdSpecification identityIdSpecification = new IdentityIdSpecification(identityId);
            return this.IdentityRepository.FindIdentity(identityIdSpecification).First();
        }

        public List<Identity> FindIdentityByUserId(Guid userId)
        {
            IdentityUserIdSpecification identityUserIdSpecification = new IdentityUserIdSpecification(userId);
            return this.IdentityRepository.FindIdentity(identityUserIdSpecification).ToList();
        }

        public void RemoveIdentity(Identity identity)
        {
            if (identity == (Identity)null)
            {
                throw new ArgumentNullException("identity");
            }

            IUnitOfWork unitOfWork = this.IdentityRepository.UnitOfWork as IUnitOfWork;
            this.IdentityRepository.Remove(identity);
            unitOfWork.CommitAndRefreshChanges();

        }

        public List<IdentityType> FindIdentityTypesByName(string identityTypeName)
        {
            IdentityTypeNameSpecification spec = new IdentityTypeNameSpecification(identityTypeName);

            return this.IdentityTypeRepository.GetBySpec(spec).ToList();
        }

        #endregion

        #region IDisposable implementations

        /// <summary>
        /// Dispose associated context with this domain service.
        /// </summary>
        public void Dispose()
        {
            if (this.IdentityRepository != null
                &&
                this.IdentityRepository.UnitOfWork != null)
            {
                this.IdentityRepository.UnitOfWork.Dispose();
            }
        }

        #endregion
    }
}
